package com.haoan.index.utils.wx;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.haoan.common.exception.ServiceException;
import com.haoan.common.utils.SecurityUtils;
import com.haoan.index.common.WebConstants;
import com.haoan.index.utils.LogUtil;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.AuthTypeEnum;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
import com.ijpay.wxpay.model.v3.*;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import static com.haoan.index.utils.wx.WxpayCertUtil.getSerialNumber;

/**
 * 微信支付工具类
 *
 * @author kwj
 */
@Slf4j
public class WxpayUtils {

    private static boolean verifySignature(IJPayHttpResponse response) {
        boolean verifySignature = false;
        try {
            verifySignature = WxPayKit.verifySignature(response, WxpayConstant.platformCertPath);
        } catch (Exception e) {
            log.error(LogUtil.buildLogMsg("微信支付下单验签错误", response.toString()), e);
        }
        return verifySignature;
    }

    /**
     * @param orderNo    订单编号，order表no
     * @param totalPrice 支付金额
     * @param info       订单备注
     * @param prepayId   微信下单返回的prepayId
     * @return 支付宝订单tradeNo
     * @return java.lang.String
     * @Description: 调用支付
     * @Author: kwj
     * @Date: 2024/9/9 10:14
     */
    public static Map<String, String> pay(String orderNo, BigDecimal totalPrice, String info, String prepayId, String notifyUrl) {
        if (prepayId == null) {
            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                    .setAppid(WxpayConstant.APP_ID).setMchid(WxpayConstant.mchId).setNotify_url(notifyUrl)
                    .setDescription(info).setOut_trade_no(orderNo)
                    .setPayer(new Payer().setOpenid(SecurityUtils.getLoginUser().getOpenId()));
            // 单位为分需要*100
            unifiedOrderModel.setAmount(new Amount().setTotal(totalPrice.multiply(new BigDecimal("100")).intValue()));
            // 过期时间
            String timeExpire = DateUtil.format(DateUtil.offsetMinute(DateUtil.date(), WebConstants.REDIS_OrderUnPayMaxMinute + 3), DatePattern.UTC_PATTERN);
            unifiedOrderModel.setTime_expire(timeExpire);
            // 发起统一下单请求
            IJPayHttpResponse response;
            String unifiedOrderModelJsonStr = JSONUtil.toJsonStr(unifiedOrderModel);
            try {
                response = WxPayApi.v3(RequestMethodEnum.POST, WxDomainEnum.CHINA.toString(), BasePayApiEnum.JS_API_PAY.toString()
                        , WxpayConstant.mchId, getSerialNumber(), null, WxpayConstant.keyPath
                        , unifiedOrderModelJsonStr
                );
                log.info(LogUtil.buildLogMsg("微信发起支付下单成功", unifiedOrderModelJsonStr, response.toString()));
            } catch (Exception e) {
                log.error(LogUtil.buildLogMsg("微信发起支付下单错误", unifiedOrderModelJsonStr), e);
                throw new ServiceException("微信发起支付下单错误:" + e.getMessage());
            }
            if (response.getStatus() == 200 && verifySignature(response)) {
                String body = response.getBody();
                JSONObject jsonObject = JSONUtil.parseObj(body);
                prepayId = jsonObject.getStr("prepay_id");
            } else {
                throw new ServiceException("微信支付下单失败" + response);
            }
        }
        try {
            Map<String, String> map = WxPayKit.jsApiCreateSign(WxpayConstant.APP_ID, prepayId, WxpayConstant.keyPath);
            log.info(LogUtil.buildLogMsg("微信支付下单生成支付串成功", map.toString()));
            map.put("prepayId", prepayId);
            return map;
        } catch (Exception e) {
            log.error(LogUtil.buildLogMsg("微信支付下单生成支付串失败", prepayId), e);
            throw new ServiceException("微信支付下单生成支付串失败");
        }
    }

    /**
     * 商户订单号查询详情
     *
     * @param outTradeNo
     * @return
     */
    public static JSONObject query(String outTradeNo) {
        JSONObject respJson = new JSONObject();
        Map<String, String> params = new HashMap<>(16);
        params.put("mchid", WxpayConstant.mchId);
        IJPayHttpResponse response = null;
        try {
            response = WxPayApi.v3(
                    RequestMethodEnum.GET, WxDomainEnum.CHINA.toString(),
                    String.format(BasePayApiEnum.ORDER_QUERY_BY_OUT_TRADE_NO.toString(), outTradeNo),
                    WxpayConstant.mchId, getSerialNumber(), null,
                    WxpayConstant.keyPath, params, AuthTypeEnum.RSA.getCode()
            );
        } catch (Exception e) {
            log.error(LogUtil.buildLogMsg("微信发起支付查询订单错误", outTradeNo), e);
        }
        if (response != null && response.getStatus() == 200 && verifySignature(response)) {
            respJson = JSONUtil.parseObj(response.getBody());
        }
        return respJson;
    }

    /**
     * 商户订单号关闭订单
     *
     * @param outTradeNo
     * @return
     */
    public static boolean close(String outTradeNo) {
        try {
            Map<String, String> params = new HashMap<>(16);
            params.put("mchid", WxpayConstant.mchId);
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethodEnum.POST,  // 使用POST请求关闭订单
                    WxDomainEnum.CHINA.toString(),
                    String.format(BasePayApiEnum.CLOSE_ORDER_BY_OUT_TRADE_NO.toString(), outTradeNo),
                    WxpayConstant.mchId,
                    getSerialNumber(),
                    null,
                    WxpayConstant.keyPath,
                    JSONUtil.toJsonStr(params),
                    AuthTypeEnum.RSA.getCode()
            );
            // 判断状态码，微信接口关闭订单没有应答包体
            if (response.getStatus() == 200) {
                return true;
            } else {
                log.error(LogUtil.buildLogMsg("微信关闭订单错误", outTradeNo, JSONUtil.toJsonStr(response)));
                return false;
            }
        } catch (Exception e) {
            log.error(LogUtil.buildLogMsg("微信关闭订单错误", outTradeNo), e);
            return false;
        }
    }

    /**
     * 退款
     *
     * @param orderNo       本地订单编号
     * @param transactionId 原支付交易订单号
     * @param refundPrice   退款金额
     * @param totalPrice    原订单总金额
     */
    public static void refund(String orderNo, String transactionId, BigDecimal refundPrice, BigDecimal totalPrice, String notifyUrl) {
        RefundModel refundModel = new RefundModel()
                .setOut_refund_no(orderNo)
                .setTransaction_id(transactionId)
                .setReason("正常退款")
                .setNotify_url(notifyUrl)
                .setAmount(new RefundAmount().setRefund(refundPrice.multiply(new BigDecimal("100")).intValue()).setTotal(totalPrice.multiply(new BigDecimal("100")).intValue()).setCurrency("CNY"));
        String jsonStr = JSONUtil.toJsonStr(refundModel);
        IJPayHttpResponse response;
        try {
            response = WxPayApi.v3(
                    RequestMethodEnum.POST,
                    WxDomainEnum.CHINA.toString(),
                    BasePayApiEnum.REFUND.toString(),
                    WxpayConstant.mchId,
                    getSerialNumber(),
                    null,
                    WxpayConstant.keyPath,
                    jsonStr
            );
            log.info(LogUtil.buildLogMsg("微信发起退单申请成功", jsonStr, response.toString()));
        } catch (Exception e) {
            log.error(LogUtil.buildLogMsg("微信发起退单申请错误", jsonStr), e);
            throw new ServiceException("微信发起退单申请错误:" + e.getMessage());
        }
        if (!verifySignature(response)) {
            throw new ServiceException("微信退单申请验签错误");
        }
    }


    public static void main(String[] args) {

    }
}
